package com.thirdguardian.sign.signv3;

import com.thirdguardian.sign.comm.CommUtils;
import com.thirdguardian.sign.comm.ConstStr;

import java.security.PrivateKey;
import java.security.PublicKey;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 签名 生成签名时，需要私钥，验证签名时需要私钥
 * @author Administrator
 */
public class SignV3Utils {

    /**
     * 生成签名
     *
     * @param appId
     * @param urlSuffix
     * @param privateKey
     * @param body
     * @return
     * @throws Exception
     */
    public static String buildSignToken(String appId, String urlSuffix, PrivateKey privateKey, String body) throws Exception {
        DateFormat df = new SimpleDateFormat(ConstStr.TIME_FORMAT_STR);
        String timestamp = df.format(new Date());
        String nonceStr = CommUtils.generateStr();
        return WxPaySignKitV3.buildAuthorization(appId, urlSuffix, privateKey, body,
                nonceStr, timestamp);
    }

    /**
     * 验证签名
     *
     * @param oAuthToken
     * @return
     * @throws Exception
     */
    public static boolean verifySignToken(String oAuthToken, String body, PublicKey publicKey) throws Exception {
        String oAuthStr = getOAuthStr(oAuthToken);
        String timestamp = getSignParamMap(oAuthStr, ConstStr.TIMESTAMP);
        String nonceStr = getSignParamMap(oAuthStr, ConstStr.NONCE_STR);
        String signature = getSignParamMap(oAuthStr, ConstStr.SIGN_NATURE);
        String urlSuffix = getSignParamMap(oAuthStr, ConstStr.SIGN_URL_SUFFIX);
        String appId = getSignParamMap(oAuthStr, ConstStr.APP_ID);
        return WxPaySignKitV3.verifySignature(appId, urlSuffix, signature, body, nonceStr, timestamp, publicKey);
    }

    private static String getOAuthStr(String oAuthToken) throws Exception {
        if (oAuthToken.startsWith(ConstStr.SIGN_AUTH_TYPE)) {
            // 去掉令牌前缀
            return oAuthToken.replace(ConstStr.SIGN_AUTH_TYPE + " ", "");
        } else {
            throw new Exception("签名验证失败，不符合签名签");
        }
    }

    private static String getSignParamMap(String oAuthStr, String key) {
        return Arrays.stream(oAuthStr.split(",")).map(str -> {
            return matchKey(str, key);
        }).filter(Objects::nonNull).collect(Collectors.joining());
    }

    private static String matchKey(String str, String key) {
        if (str.startsWith(key + "=")) {
            return str.substring(key.length() + 2, str.length() - 1);
        }
        return null;
    }
}
